bitkeeper revision 1.1159.258.93 (425ed73d07ZuW2sSaCdiIwlCRXD8IQ)
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 14 Apr 2005 20:49:01 +0000 (20:49 +0000)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Thu, 14 Apr 2005 20:49:01 +0000 (20:49 +0000)
Improved handling of non-RAM pages. Deal with RAM holes.
Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/memory.c
xen/common/grant_table.c
xen/include/asm-x86/page.h

index e82f5aa8c818dd707f6051b208f8ba4a4cb13d55..6fb5b059b103081a854d2d5b4634d1652d74746a 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/domain_page.h>
 #include <asm/ldt.h>
+#include <asm/e820.h>
 
 #ifdef VERBOSE
 #define MEM_LOG(_f, _a...)                           \
@@ -168,7 +169,8 @@ void __init init_frametable(void)
 
 void arch_init_memory(void)
 {
-    unsigned long i;
+    unsigned long i, j, pfn, nr_pfns;
+    struct pfn_info *page;
 
     /*
      * We are rather picky about the layout of 'struct pfn_info'. The
@@ -203,8 +205,8 @@ void arch_init_memory(void)
 
     /*
      * Initialise our DOMID_IO domain.
-     * This domain owns no pages but is considered a special case when
-     * mapping I/O pages, as the mappings occur at the priv of the caller.
+     * This domain owns I/O pages that are within the range of the pfn_info
+     * array. Mappings occur at the priv of the caller.
      */
     dom_io = alloc_domain_struct();
     atomic_set(&dom_io->refcnt, 1);
@@ -213,11 +215,40 @@ void arch_init_memory(void)
     /* M2P table is mappable read-only by privileged domains. */
     for ( i = 0; i < 1024; i++ )
     {
-        frame_table[m2p_start_mfn+i].count_info        = PGC_allocated | 1;
-       /* gdt to make sure it's only mapped read-only by non-privileged
-          domains. */
-        frame_table[m2p_start_mfn+i].u.inuse.type_info = PGT_gdt_page | 1;
-        frame_table[m2p_start_mfn+i].u.inuse.domain    = dom_xen;
+       /* Ensure it's mapped read-only by guests (use GDT type). */
+        page = &frame_table[m2p_start_mfn+i];
+        page->count_info        = PGC_allocated | 1;
+        page->u.inuse.type_info = PGT_gdt_page | PGT_validated | 1;
+        page->u.inuse.domain    = dom_xen;
+    }
+
+    /* First 1MB of RAM is historically marked as I/O. */
+    for ( i = 0; i < 0x100; i++ )
+    {
+        page = &frame_table[i];
+        page->count_info        = PGC_allocated | 1;
+        page->u.inuse.type_info = PGT_writable_page | PGT_validated | 1;
+        page->u.inuse.domain    = dom_io;
+    }
+    /* Any non-RAM areas in the e820 map are considered to be for I/O. */
+    for ( i = 0; i < e820.nr_map; i++ )
+    {
+        if ( e820.map[i].type == E820_RAM )
+            continue;
+        pfn = e820.map[i].addr >> PAGE_SHIFT;
+        nr_pfns = (e820.map[i].size +
+                   (e820.map[i].addr & ~PAGE_MASK) +
+                   ~PAGE_MASK) >> PAGE_SHIFT;
+        for ( j = 0; j < nr_pfns; j++ )
+        {
+            if ( !pfn_valid(pfn+j) )
+                continue;
+            page = &frame_table[pfn+j];
+            page->count_info        = PGC_allocated | 1;
+            page->u.inuse.type_info = PGT_writable_page | PGT_validated | 1;
+            page->u.inuse.domain    = dom_io;
+        }
     }
 }
 
@@ -298,13 +329,7 @@ static int get_page_from_pagenr(unsigned long page_nr, struct domain *d)
 {
     struct pfn_info *page = &frame_table[page_nr];
 
-    if ( unlikely(!pfn_is_ram(page_nr)) )
-    {
-        MEM_LOG("Pfn %08lx is not RAM", page_nr);
-        return 0;
-    }
-
-    if ( unlikely(!get_page(page, d)) )
+    if ( unlikely(!pfn_valid(page_nr)) || unlikely(!get_page(page, d)) )
     {
         MEM_LOG("Could not get page ref for pfn %08lx", page_nr);
         return 0;
@@ -410,20 +435,25 @@ get_page_from_l1e(
         return 0;
     }
 
-    if ( unlikely(!pfn_is_ram(pfn)) )
+    if ( unlikely(!pfn_valid(pfn)) ||
+         unlikely(page->u.inuse.domain == dom_io) )
     {
-        /* Revert to caller privileges if FD == DOMID_IO. */
+        /* DOMID_IO reverts to caller for privilege checks. */
         if ( d == dom_io )
             d = current;
 
-        if ( IS_PRIV(d) )
-            return 1;
+        if ( (!IS_PRIV(d)) &&
+             (!IS_CAPABLE_PHYSDEV(d) || !domain_iomem_in_pfn(d, pfn)) )
+        {
+            MEM_LOG("Non-privileged attempt to map I/O space %08lx", pfn);
+            return 0;
+        }
 
-        if ( IS_CAPABLE_PHYSDEV(d) )
-            return domain_iomem_in_pfn(d, pfn);
+        /* No reference counting for out-of-range I/O pages. */
+        if ( !pfn_valid(pfn) )
+            return 1;
 
-        MEM_LOG("Non-privileged attempt to map I/O space %08lx", pfn);
-        return 0;
+        d = dom_io;
     }
 
     return ((l1v & _PAGE_RW) ?
@@ -468,7 +498,7 @@ static void put_page_from_l1e(l1_pgentry_t l1e, struct domain *d)
     struct pfn_info *page = &frame_table[pfn];
     struct domain   *e;
 
-    if ( !(l1v & _PAGE_PRESENT) || !pfn_is_ram(pfn) )
+    if ( !(l1v & _PAGE_PRESENT) || !pfn_valid(pfn) )
         return;
 
     e = page->u.inuse.domain;
@@ -1114,7 +1144,7 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
         gntref = (grant_ref_t)((val & 0xFF00) | ((ptr >> 2) & 0x00FF));
         
         if ( unlikely(IS_XEN_HEAP_FRAME(page)) ||
-             unlikely(!pfn_is_ram(pfn)) ||
+             unlikely(!pfn_valid(pfn)) ||
              unlikely((e = find_domain_by_id(domid)) == NULL) )
         {
             MEM_LOG("Bad frame (%08lx) or bad domid (%d).\n", pfn, domid);
index 1a207711e2f9fa61fd1b0274c2136565f75efdcd..f62111334271367c0b4263fbbad5fe088f9e155f 100644 (file)
@@ -169,7 +169,7 @@ __gnttab_map_grant_ref(
 
         /* rmb(); */ /* not on x86 */
         frame = sha->frame;
-        if ( unlikely(!pfn_is_ram(frame)) || 
+        if ( unlikely(!pfn_valid(frame)) || 
              unlikely(!((flags & GNTMAP_readonly) ? 
                         get_page(&frame_table[frame], rd) : 
                         get_page_and_type(&frame_table[frame], rd, 
index c016f4b5e035cbee92d6ba81432c4c6d31a64e12..103455846af3cecab6275e2d795c96f3b0fbe1db 100644 (file)
@@ -105,14 +105,7 @@ typedef struct { unsigned long pt_lo; } pagetable_t;
 #define pfn_to_page(_pfn)       (frame_table + (_pfn))
 #define phys_to_page(kaddr)     (frame_table + ((kaddr) >> PAGE_SHIFT))
 #define virt_to_page(kaddr)    (frame_table + (__pa(kaddr) >> PAGE_SHIFT))
-#define VALID_PAGE(page)       ((page - frame_table) < max_mapnr)
-
-/*
- * NB. We don't currently track I/O holes in the physical RAM space.
- * For now we guess that I/O devices will be mapped in the first 1MB
- * (e.g., VGA buffers) or beyond the end of physical RAM.
- */
-#define pfn_is_ram(_pfn)        (((_pfn) > 0x100) && ((_pfn) < max_page))
+#define pfn_valid(_pfn)         ((_pfn) < max_page)
 
 /* High table entries are reserved by the hypervisor. */
 #define DOMAIN_ENTRIES_PER_L2_PAGETABLE            \